//
//  DawnFrame.swift
//  DawnFoundation
//
//  Created by 崔成成 on 2021/8/5.
//

import UIKit

public enum DawnRectUpdateType {
    case minX(CGFloat, DawnRectType)
    case minY(CGFloat, DawnRectType)
    case midX(CGFloat, DawnRectType)
    case midY(CGFloat, DawnRectType)
    case maxY(CGFloat, DawnRectType)
    case maxX(CGFloat, DawnRectType)
    case width(CGFloat, DawnRectType)
    case height(CGFloat, DawnRectType)
       
    
    func rectValue(_ rect: inout DawnRect) -> CGRect {
        switch self {
            case .minX(let x, let dependType):
                switch dependType {
                    case .midX:
                        return rect.updateHorizontal(minX: x, midX: rect.midX)
                    case .maxX:
                        return rect.updateHorizontal(minX: x, maxX: rect.maxX)
                    default:
                        return rect.updateHorizontal(minX: x, width: rect.width)
                }
            case .midX(let x, let dependType):
                switch dependType {
                    case .minX:
                        return rect.updateHorizontal(minX: rect.minX, midX: x)
                    case .maxX:
                        return rect.updateHorizontal(maxX: rect.maxX, midX: x)
                    default:
                        return rect.updateHorizontal(midX: x, width: rect.width)
                }
            case .maxX(let x, let dependType):
                switch dependType {
                    case .midX:
                        return rect.updateHorizontal(maxX: x, midX: rect.midX)
                    case .minX:
                        return rect.updateHorizontal(minX: rect.minX, maxX: x)
                    default:
                        return rect.updateHorizontal(maxX: x, width: rect.width)
                }
            case .width(let x, let dependType):
                switch dependType {
                    case .midX:
                        return rect.updateHorizontal(midX: rect.midX, width: x)
                    case .maxX:
                        return rect.updateHorizontal(maxX: rect.maxX, width: x)
                    default:
                        return rect.updateHorizontal(minX: rect.minX, width: x)
                }
            case .minY(let x, let dependType):
                switch dependType {
                    case .midY:
                        return rect.updateVertical(minY: x, midY: rect.midY)
                    case .maxY:
                        return rect.updateVertical(minY: x, maxY: rect.maxY)
                    default:
                        return rect.updateVertical(minY: x, height: rect.height)
                }
            case .midY(let x, let dependType):
                switch dependType {
                    case .minY:
                        return rect.updateVertical(minY: rect.minY, midY: x)
                    case .maxY:
                        return rect.updateVertical(maxY: rect.maxY, midY: x)
                    default:
                        return rect.updateVertical(midY: x, height: rect.height)
                }
            case .maxY(let x, let dependType):
                switch dependType {
                    case .midY:
                        return rect.updateVertical(maxY: x, midY: rect.midY)
                    case .minY:
                        return rect.updateVertical(minY: rect.minY, maxY: x)
                    default:
                        return rect.updateVertical(maxY: x, height: rect.height)
                }
            case .height(let x, let dependType):
                switch dependType {
                    case .midY:
                        return rect.updateVertical(midY: rect.midY, height: x)
                    case .maxY:
                        return rect.updateVertical(maxY: rect.maxY, height: x)
                    default:
                        return rect.updateVertical(minY: rect.minY, height: x)
                }
        }
    }
}

public enum DawnRectType {
    case minX
    case minY
    case midX
    case midY
    case maxY
    case maxX
    case width
    case height
}

extension UIView {
    
    private struct AssociatedKey {
        static var dawn_rect: String = "dawn_rect_key"
    }
    
    private var dawnRect: DawnRect {
        set {
            objc_setAssociatedObject(self, &AssociatedKey.dawn_rect, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &AssociatedKey.dawn_rect) as? DawnRect ?? DawnRect()
        }
    }
    
    func clearFrame() {
        dawnRect.clear()
    }
    
    @discardableResult
    public func width(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(width: x)
        return self
    }
    
    @discardableResult
    public func height(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(height: x)
        return self
    }
    
    @discardableResult
    public func top(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(minY: x)
        return self
    }
    
    @discardableResult
    public func left(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(minX: x)
        return self
    }
    
    @discardableResult
    public func right(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(maxX: x)
        return self
    }
    
    @discardableResult
    public func bottom(_ x: CGFloat)->UIView {

        frame = dawnRect.dawn(maxY: x)
        return self
    }
    
    @discardableResult
    public func centerX(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(midX: x)
        return self
    }
    
    @discardableResult
    public func centerY(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(midY: x)
        return self
    }
    
    @discardableResult
    public func left_right(_ v: UIView, x: CGFloat = 0)->UIView {
        if (superview?.isEqual(v)) == true {
            frame = dawnRect.dawn(minX: x, maxX: v.frame.width - x)
        }else {
            frame = dawnRect.dawn(minX: v.frame.minX + x, maxX: v.frame.maxX - x)
        }
        return self
    }
    
    @discardableResult
    public func top_bottom(_ v: UIView)->UIView {
        if (superview?.isEqual(v)) == true {
            frame = dawnRect.dawn(minY: 0, maxY: v.frame.height)
        }else {
            frame = dawnRect.dawn(minY: v.frame.minY, maxY: v.frame.maxY)
        }
        return self
    }
    
    @discardableResult
    public func size(_ v: UIView)->UIView {
        frame = dawnRect.dawn(width: v.frame.width, height: v.frame.height)
        return self
    }
    
    @discardableResult
    public func size(_ x: CGSize)->UIView {
        frame = dawnRect.dawn(width: x.width, height: x.height)
        return self
    }
    
    @discardableResult
    public func equal(_ v: UIView)->UIView {
        if v.superview?.isEqual(v) == true {
            frame = v.bounds
        }else {
            frame = v.frame
        }
        return self
    }
    
    @discardableResult
    public func outer(_ v: UIView, insets: UIEdgeInsets)->UIView {
        dawnRect.clear()
        frame = dawnRect.dawn(minX: v.frame.minX + insets.left,
                              minY: v.frame.minY + insets.top,
                              maxX: v.frame.maxX - insets.right,
                              maxY: v.frame.maxY - insets.bottom)
        return self
    }
    
    @discardableResult
    public func inner(_ v: UIView, insets: UIEdgeInsets)->UIView {
        dawnRect.clear()
        frame = dawnRect.dawn(minX: insets.left,
                              minY:  insets.top,
                              maxX: v.frame.width - insets.right,
                              maxY: v.frame.height - insets.bottom)
        return self
    }
    
    @discardableResult
    public func left_offsetTop(_ v: UIView, x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minX: v.frame.minX, minY: v.frame.maxY + x)
        return self
    }
    
    @discardableResult
    public func width_height(_ x: CGFloat)->UIView {
        frame = dawnRect.dawn(width: x, height: x)
        return self
    }
    
    @discardableResult
    public func width_height(_ v: UIView)->UIView {
        frame = dawnRect.dawn(width: v.frame.width, height: v.frame.height)
        return self
    }
    
    @discardableResult
    public func right_offsetTop(_ v: UIView, x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minY: v.frame.maxY + x, maxX: v.frame.maxX)
        return self
    }
    
    @discardableResult
    public func left_right_offsetTop(_ v: UIView,
                                     margin: CGFloat = 0,
                                     x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minX: v.frame.minX + margin,
                              minY: v.frame.maxY + x,
                              maxX: v.frame.maxX - margin)
        return self
    }
    
    @discardableResult
    public func centerY_offsetLeft(_ v: UIView, x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minX: v.frame.minX + x, midY: v.frame.midY)
        return self
    }
    
    @discardableResult
    public func centerX_offsetTop(_ v: UIView, x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minY: v.frame.maxY + x, midX: v.frame.midX)
        return self
    }
    
    @discardableResult
    public func left_right_height_offsetTop(_ v: UIView, x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minX: v.frame.minX,
                              minY: v.frame.maxY + x,
                              maxX: v.frame.maxX,
                              height: v.frame.height)
        return self
    }
    
    @discardableResult
    public func top_bottom_offsetLeft(_ v: UIView, x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minX: v.frame.maxX + x,
                              minY: v.frame.minY,
                              maxY: v.frame.maxY)
        return self
    }
    
    @discardableResult
    public func top_bottom_width_offsetLeft(_ v: UIView, x: CGFloat = 0)->UIView {
        frame = dawnRect.dawn(minX: v.frame.maxX + x,
                              minY: v.frame.minY,
                              maxY: v.frame.maxY,
                              width: v.frame.width)
        return self
    }
    
    @discardableResult
    public func remainCenter(_ v: UIView, isVertical: Bool = true, x: CGFloat = 0)-> UIView {
        guard let superV = superview else { return self }
        if isVertical {
            let distance = superV.bounds.height - v.frame.maxY
            let mid = v.frame.maxY + distance/2 + x
            frame = dawnRect.dawn(midY: mid)
        }else {
            let distance = superV.bounds.width - v.frame.maxX
            let mid = v.frame.maxX + distance/2 + x
            frame = dawnRect.dawn(midX: mid)
        }
        return self
    }
    
    @discardableResult
    public func update(type: DawnRectUpdateType)-> UIView {
        frame = type.rectValue(&dawnRect)
        return self
    }

    public func horizontalAverage(sub views: [UIView],
                                  height: CGFloat,
                                  space: CGFloat = 0,
                                  insetLeft: CGFloat = 0,
                                  insetRight: CGFloat = 0,
                                  top: CGFloat = 0) {
        let itemW = ((frame.width - insetLeft - insetRight) - CGFloat(views.count - 1) * space) / CGFloat(views.count)
        for i in 0..<views.count {
            let v = views[i]
            v.frame = CGRect(x: insetLeft + (itemW + space) * CGFloat(i), y: top, width: itemW, height: height)
            if v.superview == nil {
                addSubview(v)
            }
        }
    }
    
    
}


